home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
EnigmA Amiga Run 1996 June
/
EnigmA AMIGA RUN 08 (1996)(G.R. Edizioni)(IT)[!][issue 1996-06][EARSAN CD VII].iso
/
earcd
/
utmisc1
/
chktex.lha
/
chktex
/
Utility.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-04-30
|
15KB
|
776 lines
/*
* ChkTeX v1.4, utility functions.
* Copyright (C) 1995-96 Jens T. Berger Thielemann
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* Contact the author at:
* Jens Berger
* Spektrumvn. 4
* N-0666 Oslo
* Norway
* E-mail: <jensthi@ifi.uio.no>
*
*
*/
#include "ChkTeX.h"
/***************************** SUPPORT FUNCTIONS ************************/
/*
* Copies a string with a maximum length of `len' starting at `pos' in
* `source' into `dest'.
* Returns -1 if the pos value is beyond the length of the source value,
* else NULL.
*/
#ifndef HAVE_STRMID
WORD strmid(const STRPTR source, STRPTR dest, ULONG pos, LONG len)
{
STRPTR Start;
WORD Retval = -1;
if(len >= 0)
{
if(strlen(source) > pos)
{
Start = &source[pos];
while((len-- > 0) && (*dest++ = *Start++))
;
if(len == -1)
Retval = 0;
}
}
else
Retval = 0L;
*dest = 0;
return(Retval);
}
#endif
/*
* Determine whether a file exists.
*
*/
BOOL fexists(STRPTR Filename)
{
BOOL Retval = FALSE;
#if defined(F_OK) && defined(R_OK) && defined(HAVE_ACCESS)
Retval = access(Filename, F_OK|R_OK) == 0;
#else
FILE *fh;
if(fh = fopen(Filename, "r"))
{
Retval = TRUE;
fclose(fh);
}
#endif
return(Retval);
}
/*
* 'Safe' memset() replacement.
* Just tries to check the parameters, so that the risk of killing
* innocent memory is lowered.
* Please note that the `n' parameter now is an signed longword, not
* an size_t. Won't permit that `n' exceeds BUFLEN, nor negative sizes.
* Returns `to' if some memset()'ing was done, NULL if not.
*/
APTR sfmemset(APTR to, int c, LONG n)
{
if(to && (n > 0))
{
n = min(n, BUFSIZ);
return(memset(to, c, (size_t) n));
}
return(NULL);
}
/*
* Concatenates the `File' string to the `Dir' string, leaving the result
* in the `Dir' buffer. Takes care of inserting `directory' characters;
* if we've got the strings "/usr/foo" and "bar", we'll get
* "/usr/foo/bar".
*
* Behaviour somewhat controlled by the macros SLASH and DIRCHARS in the
* .h file.
*
*/
void tackon(STRPTR Dir, const STRPTR File)
{
UBYTE EndC;
ULONG SLen;
if(Dir && (SLen = strlen(Dir)))
{
EndC = Dir[SLen -1];
ifn(strchr(DIRCHARS, EndC))
{
Dir[SLen++] = SLASH;
Dir[SLen ] = 0L;
}
}
strcat(Dir, File);
}
/*
* Quick replace function
* Replaces every occurrence of a character in a string with another one.
*/
void strrep(STRPTR String, /* String to replace within. */
const UBYTE From, /* Character to search for. */
const UBYTE To) /* Character to put instead. */
{
int c;
while((c = *String++))
{
if(c == From)
String[-1] = To;
}
}
/*
* Strips tail and/or front of a string
* Kills trailing/leading spaces. The macro/function SKIP_STRIP(char c)
* is used to decide whether a space should be skipped. This function
* should return TRUE if the character should be skipped, FALSE if not.
* Returns the string which was passed onto it.
*/
STRPTR strip(STRPTR str, /* String to strip */
const WORDBITS flags)
/* One of the following: */
/* STRP_LFT - Strips leading blanks */
/* STRP_RGT - Strips trailing blanks */
/* STRP_BTH - Strips on both sides */
{
STRPTR bufptr = str, nlptr;
UBYTE c;
if(bufptr && (c = *bufptr))
{
if(flags & STRP_LFT)
{
if(SKIP_STRIP(c) && c)
{
do
{
c = *++bufptr;
} while(SKIP_STRIP(c) && c);
}
}
if(flags & STRP_RGT)
{
if(c && *bufptr)
{
nlptr = bufptr;
while(*++nlptr);
do
{
nlptr[0] = 0;
c = *--nlptr;
} while(SKIP_STRIP(c) && c && (nlptr > bufptr));
}
else
*bufptr = 0;
}
}
return(bufptr);
}
/*
* Converts all the chars in the string passed into uppercase.
*/
#ifndef HAVE_STRUPR
STRPTR strupr(STRPTR String)
{
STRPTR Bufptr;
UBYTE TmpC;
for(Bufptr = String;
(TmpC = *Bufptr);
Bufptr++)
*Bufptr = toupper(TmpC);
return(String);
}
#endif
/*
* Returns a duplicate of the string passed.
*/
#ifndef HAVE_STRDUP
STRPTR strdup(const STRPTR String)
{
STRPTR Retval = NULL;
size_t Len;
if(String)
{
Len = strlen(String) + 1;
if((Retval = malloc(Len)))
{
memcpy(Retval, String, Len);
}
}
return(Retval);
}
#endif
#ifndef HAVE_STRCASECMP
int strcasecmp(char* a, char *b)
{
int aa, bb;
do
{
aa = *a++;
bb = *b++;
} while(aa && ((aa == bb) || (toupper(aa) == toupper(bb))));
/* bb != 0 is implicit */
return(toupper(aa) - toupper(bb));
}
#endif
/*
* Not all reallocs are intelligent enough to handle NULL's as
* parameters. This fixes this.
*/
void *saferealloc(void *b, size_t n)
{
APTR Retval = NULL;
if(b)
{
if(n)
Retval = realloc(b, n);
else
free(b);
}
else
Retval = malloc(n);
return(Retval);
}
/*
* Repeatedly writes the From string over To so that we overwrite Len bytes.
* Does nothing if passed empty/NULL string.
*/
void strwrite (STRPTR To, STRPTR From, ULONG Len)
{
ULONG i, j;
ULONG FromLen = strlen(From);
Len = min(Len, BUFSIZ);
if(To && From)
{
switch(FromLen)
{
case 0:
break;
case 1:
memset(To, *From, Len);
break;
default:
for(i = j = 0;
i < Len;
i++, j++)
{
if(j >= FromLen)
j = 0;
To[i] = From[j];
}
}
}
}
/*
* Checks whether Cmp comes after Str.
*
*/
int strafter(STRPTR Str, STRPTR Cmp)
{
return(strncmp(Str, Cmp, strlen(Cmp)));
}
/*
* Checks whether Cmp comes before Str. Returns 0 if so, non-zero if not.
*
*/
int strinfront(STRPTR Str, STRPTR Cmp)
{
int CmpLen = strlen(Cmp);
if(*Cmp)
{
Str++;
Cmp += CmpLen;
while((*--Cmp == *--Str) && (--CmpLen > 0))
;
return(CmpLen);
}
else
return(1);
}
/*************************** WORDLIST HANDLING **************************/
/*
* Inserts a duplicate of `Word' into the `Wordlist' structure. You do thus
* not need to make a duplicate of `Word' yourself.
*/
BOOL InsertWord(const STRPTR Word, struct WordList *WL)
{
STRPTR WrdCpy;
if((WrdCpy = strdup(Word)))
{
if(StkPush(WrdCpy, &WL->Stack))
{
WL->Sorted = FALSE;
return(TRUE);
}
free(WrdCpy);
}
return(FALSE);
}
/*
* Query whether a `Word' is previously InsertWord()'ed into the WL
* structure. Does case-sensitive comparison.
*/
BOOL HasWord(const STRPTR Word, struct WordList *WL)
{
if(WL && WL->Stack.Used && Word)
{
ifn(WL->Sorted)
{
qsort(&WL->Stack.Data[0], (size_t) WL->Stack.Used,
sizeof(APTR), &str_cmp);
WL->Sorted = TRUE;
}
if(bsearch(&Word, &WL->Stack.Data[0], (size_t) WL->Stack.Used,
sizeof(APTR), &str_cmp))
return(TRUE);
}
return(FALSE);
}
int str_cmp(const void *a, const void *b)
{
return(strcmp(*((STRPTR *) a), *((STRPTR *) b)));
}
/************************** GENERIC STACK ******************************/
/*
* Push something onto a stack. Returns TRUE if successful, else FALSE.
* Note: You can not push a NULL Data element.
*/
BOOL StkPush(const APTR Data, struct Stack *Stack)
{
ULONG NewSize;
APTR *NewBuf;
if(Data && Stack)
{
if(Stack->Used >= Stack->Size)
{
NewSize = Stack->Size + MINPUDDLE;
if((NewBuf = saferealloc(Stack->Data,
(size_t) NewSize * sizeof(APTR))))
{
Stack->Size = NewSize;
Stack->Data = NewBuf;
}
else
return(FALSE);
}
Stack->Data[Stack->Used++] = Data;
return(TRUE);
}
return(FALSE);
}
/*
* Pops an element from the stack.
*
*/
APTR StkPop(struct Stack *Stack)
{
APTR Retval = NULL;
if(Stack && (Stack->Used > 0))
{
Retval = Stack->Data[--Stack->Used];
#ifdef NO_DIRTY_TRICKS
{
APTR *NewBuf;
if(Stack->Used < (Stack->Size/2))
{
ULONG NewSize;
NewSize = Stack->Size - MINPUDDLE;
NewSize = max(NewSize, MINPUDDLE);
if(NewBuf = saferealloc(Stack->Data,
(size_t) NewSize * sizeof(APTR)))
{
Stack->Size = NewSize;
Stack->Data = NewBuf;
}
}
}
#endif
}
return(Retval);
}
/*
* Returns the topmost element of the stack.
*/
APTR StkTop(struct Stack *Stack)
{
if(Stack && (Stack->Used > 0))
return(Stack->Data[Stack->Used - 1]);
else
return(NULL);
}
/****************************** INPUT STACK *****************************/
BOOL PushFileName(STRPTR Name, struct Stack *stack)
{
FILE *fh;
UBYTE NameBuf [BUFSIZ];
ULONG Counter;
if(Name && stack)
{
for(Counter = 0;
Counter < TeXInputs.Stack.Used;
Counter++)
{
strcpy(NameBuf, TeXInputs.Stack.Data[Counter]);
strcat(NameBuf, Name);
if((fh = fopen(NameBuf, "r")))
break;
strcat(NameBuf, ".tex");
if((fh = fopen(NameBuf, "r")))
break;
}
ifn(fh = fopen(NameBuf, "r")) {
PrintPrgErr(pmNoTeXOpen, NameBuf);
return(FALSE);
}
return(PushFile(NameBuf, fh, stack));
}
return(FALSE);
}
BOOL PushFile(STRPTR Name, FILE *fh, struct Stack *stack)
{
struct FileNode *fn;
if(Name && fh && stack)
{
if((fn = malloc(sizeof(struct FileNode))))
{
if((fn->Name = strdup(Name)))
{
fn->fh = fh;
fn->Line = 0L;
if(StkPush(fn, stack))
return(TRUE);
free(fn->Name);
}
free(fn);
}
PrintPrgErr(pmNoStackMem);
}
return(FALSE);
}
STRPTR FGetsStk(STRPTR Dest, ULONG len, struct Stack *stack)
{
struct FileNode *fn;
STRPTR Retval = NULL;
if((fn = StkTop(stack))) {
do {
if((Retval = fgets(Dest, (int) len, fn->fh))) {
fn->Line++;
break;
}
fn = StkPop(stack);
fclose(fn->fh);
free(fn);
} while(!Retval && (fn = StkTop(stack)));
}
return(Retval);
}
STRPTR CurStkName(struct Stack *stack)
{
struct FileNode *fn;
static
STRPTR LastName = "";
if(PseudoInName && (stack->Used <= 1))
return(PseudoInName);
else
{
if((fn = StkTop(stack)))
return(LastName = fn->Name);
else
return(LastName);
}
}
FILE *CurStkFile(struct Stack *stack)
{
struct FileNode *fn;
if((fn = StkTop(stack)))
return(fn->fh);
else
return(NULL);
}
ULONG CurStkLine(struct Stack *stack)
{
struct FileNode *fn;
static
ULONG LastLine = 0L;
if((fn = StkTop(stack)))
return(LastLine = fn->Line);
else
return(LastLine);
}
/************************** CHARACTER STACK ******************************/
/*
* Pushes the character on the stack.
*/
BOOL PushChar(const UBYTE c, const ULONG Line,
const ULONG Column, struct Stack *Stk,
const STRPTR LineCpy)
{
UBYTE Buf[2];
Buf[0] = c; Buf[1] = 0;
return(PushErr( Buf, Line, Column, 1, LineCpy, Stk));
}
BOOL PushErr( const STRPTR Data, const ULONG Line,
const ULONG Column, const ULONG ErrLen,
const STRPTR LineCpy, struct Stack *Stk)
{
struct ErrInfo *ci;
if((ci = malloc(sizeof(struct ErrInfo))))
{
if((ci->Data = strdup(Data)))
{
ci->File = CurStkName(&InputStack);
ci->Line = Line;
ci->ErrLen = ErrLen;
ci->Column = Column;
ci->LineBuf = LineCpy;
if(StkPush(ci, Stk))
return(TRUE);
}
free(ci);
}
return(FALSE);
}
/*
* Returns and removes a character from the stack, returns NULL if
* the stack is empty.
*/
struct ErrInfo *PopErr(struct Stack *Stack)
{
return((struct ErrInfo *) StkPop(Stack));
}
/*
* Same as PopChar(), but lets the error alone on the stack.
*/
struct ErrInfo *TopErr(struct Stack *Stack)
{
return((struct ErrInfo *) StkTop(Stack));
}
/*
* Free all resources associated with a struct FreeInfo.
*/
void FreeErrInfo(struct ErrInfo* ei)
{
if(ei) {
if(ei->Data)
free(ei->Data);
free(ei);
}
}
/************************* OPEN/CLOSE COUNTING **************************/
/*
* Returns the index a given bracket (`()[]{}') character has in the
* BrOrder array. Returns ~0 if the character was not a bracket.
*/
LONG BrackIndex(const UBYTE c)
{
switch(c)
{
case '(':
return(0);
case ')':
return(1);
case '[':
return(2);
case ']':
return(3);
case '{':
return(4);
case '}':
return(5);
default:
return(~0L);
}
}
/*
* Counts brackets for you. Give it a bracket, and it will update the
* corresponding counter.
*/
void AddBracket(const UBYTE c)
{
LONG Index;
if((Index = BrackIndex(c)) != -1)
Brackets[Index]++;
}
/*
* Returns the character that matches the given bracket, NULL if `c'
* wasn't a bracket character.
*/
UBYTE MatchBracket(const UBYTE c)
{
ULONG Index;
UBYTE Char = 0;
if((Index = BrackIndex(c)) != ~0UL)
Char = BrOrder[Index ^ 1];
return(Char);
}